﻿#include "VulkanContext.h"

#include "VulkanDebug.h"
#include "Output/Console.h"
#include "Render/PreRender/PreRenderWindow.h"
#include "Render/PreRender/PreRenderResult.h"

#include "Platform/PlatformInterface.h"

#include "Render/Widget/VulkanWindow.h"
#include "Asset/EngineDefaultPackage.h"
#include "Material/Shader.h"
#include "Primitive/Vertex.h"

#include "Render/RenderContext.h"

#include "Shaders/CppMacros.h"

#include "Render/Texture/VulkanTexture2Ds.h"
#include "Render/Texture/VulkanTextureCubes.h"
#include "Render/Mesh/VulkanMeshs.h"
#include "Render/Material/VulkanMaterials.h"
#include "Render/Material/VulkanShaders.h"
#include "Render/Material/VulkanShader.h"

#include "Time/CPUTimeCounter.h"

CVulkanContext *CVulkanContext::Get()
{
    static CVulkanContext VulkanContext;
    return &VulkanContext;
}

CVulkanContext::~CVulkanContext()
{
    VulkanThreadRunning=false;
    //等待线程结束
    RenderThread->join();
    //等待设备结束,以便安全释放资源
    Device.waitIdle();


}

//print vulkan debug info
static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugCallback(
    VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
    VkDebugUtilsMessageTypeFlagsEXT messageType,
    const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
    void* pUserData) {
    
#ifndef DEBUG
    return VK_FALSE;
#endif

    CString Error= (char8_t*)pCallbackData->pMessage;
    
    WH::PrintLine(U"[vulkan Error]:");
    WH::PrintLine(Error);

    assert(false && "Error");

    return VK_TRUE;
}



static VKAPI_ATTR VkBool32 VKAPI_CALL VulkanDebugCallbackVerbose(
    VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
    VkDebugUtilsMessageTypeFlagsEXT messageType,
    const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
    void* pUserData) {
    
#ifndef DEBUG
    return VK_FALSE;
#endif

    CString Error= (char8_t*)pCallbackData->pMessage;

    WH::PrintLine(U"[vulkan Verbose]:");
    WH::PrintLine(Error);
    
    return VK_TRUE;
}


void CVulkanContext::Initialize()
{

    TVector<const char*> layers;
#ifdef DEBUG
    layers.Add("VK_LAYER_KHRONOS_validation");  //for vulkan debug output, But may cause CRASH,Will slow down the program
#endif
   
#ifdef DEBUG  
    const TVector<vk::ValidationFeatureEnableEXT> EnabledValidation={
        vk::ValidationFeatureEnableEXT::eDebugPrintf      //for shader debug output
    }; 

    vk::ValidationFeaturesEXT ValidationFeaturesEXT=vk::ValidationFeaturesEXT()
        .setEnabledValidationFeatures(EnabledValidation); //for shader debug output

#endif

    auto AppInfo =vk::ApplicationInfo()
    .setPApplicationName("WuhuaEngine Main Window")
    .setApplicationVersion(1)
    .setPEngineName("LunarG SDK")
    .setEngineVersion(1)
    .setApiVersion(VK_API_VERSION_1_2);

    auto InstanceExrensions=IPlatformInterface::GetPlatformInterface()->GetVulkanInstanceExtensions();


#ifdef DEBUG
    InstanceExrensions.Add(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);  //for vulkan debug output
    InstanceExrensions.Add(VK_EXT_DEBUG_REPORT_EXTENSION_NAME); //enable debug_marker

#endif
    InstanceExrensions.Add(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);  //required by VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME


    vk::InstanceCreateInfo instInfo = vk::InstanceCreateInfo()
#ifdef DEBUG  
    .setPNext(&ValidationFeaturesEXT)
#endif
        .setFlags(vk::InstanceCreateFlags())
        .setPApplicationInfo(&AppInfo)
        .setEnabledExtensionCount(static_cast<uint32_t>(InstanceExrensions.size()))
        .setPpEnabledExtensionNames(InstanceExrensions.data())
        .setEnabledLayerCount(static_cast<uint32_t>(layers.size()))
        .setPpEnabledLayerNames(layers.data());    

    try 
    {
        VkInstance = vk::createInstance(instInfo);
    }
    catch (const std::exception& e) {
        std::string Msg=std::string("Could not create a Vulkan instance: ")+e.what();
        assert(false && Msg.c_str());
    }        


#ifdef DEBUG
    //enable debug print

    VkDebugUtilsMessengerCreateInfoEXT createInfo{};  
    createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;               
    createInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
    createInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
    createInfo.pfnUserCallback = VulkanDebugCallback;
    createInfo.pUserData = nullptr; // Optional

    VkDebugUtilsMessengerCreateInfoEXT VerboseCreateInfo{};
    VerboseCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;               
    VerboseCreateInfo.messageSeverity =VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT ;
    VerboseCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
    VerboseCreateInfo.pfnUserCallback = VulkanDebugCallbackVerbose;
    VerboseCreateInfo.pUserData = nullptr; // Optional


    auto FP_vkCreateDebugUtilsMessengerEXT = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(VkInstance, "vkCreateDebugUtilsMessengerEXT");
    if (FP_vkCreateDebugUtilsMessengerEXT)
    {
        {
            VkDebugUtilsMessengerEXT Debugger;
            FP_vkCreateDebugUtilsMessengerEXT(VkInstance, &createInfo, nullptr, &Debugger);  //for output error
        }

        {
            // VkDebugUtilsMessengerEXT Debugger;
            // FP_vkCreateDebugUtilsMessengerEXT(VkInstance, &VerboseCreateInfo, nullptr, &Debugger);  //for output normal info
        }
    }
    else
    {
        assert(false&& "Failed to add vulkan debugger!");
    }   
#endif



    SelectPhysicalDevice();

    SelectQueue();
    CreateDevice();
    VkDebug::debugmarker::setup(GetDevice());

    Texture2DMangers=std::make_shared<CVulkanTexture2Ds>();
    TextureCubeMangers=std::make_shared<CVulkanTextureCubes>();
    MeshMangers=std::make_shared<CVulkanMeshs>();
    ShadersMangers=std::make_shared<CVulkanShaders>();

    MaterialsMangers[0]=std::make_shared<CVulkanMaterials>();
    MaterialsMangers[1]=std::make_shared<CVulkanMaterials>();

    VulkanThreadRunning=true;
    RenderThread =new std::thread(&CVulkanContext::VulkanThreadRun,this);

    //wait for widget render thread init
    while(!RenderThreadInitialized.load())
    {
        continue;
    }    
}


bool CVulkanContext::IsDepthFormat(vk::Format Format)
{
    return Format==vk::Format::eD16Unorm 
        || Format==vk::Format::eD32Sfloat 
        || Format==vk::Format::eD16UnormS8Uint 
        || Format==vk::Format::eD24UnormS8Uint 
        || Format==vk::Format::eD32SfloatS8Uint;
}

void CVulkanContext::SelectPhysicalDevice()
{
    int GpuCount=0;
    auto physicalDevices=VkInstance.enumeratePhysicalDevices();

    if(physicalDevices.size()<=0)
    {
        WH::PrintLine(U"can't find any device support vulkan");
    }

    //PhysicalDevice=physicalDevices[0];

    TVector<vk::PhysicalDevice> AvailablePhysicalDevices;

    for(auto PotentialPhysicalDevice:physicalDevices )
    {
        // if(PotentialPhysicalDevice.getProperties().deviceType !=vk::PhysicalDeviceType::eDiscreteGpu)
        // {
        //    continue;
        // }

        auto Extensions=PotentialPhysicalDevice.enumerateDeviceExtensionProperties();
        
        bool FoundSwapchainExtension=false; //find swapchin extension for display
        for(auto Extension:Extensions)
        {
            if(!FoundSwapchainExtension && strcmp(Extension.extensionName,VK_KHR_SWAPCHAIN_EXTENSION_NAME))
            {
                FoundSwapchainExtension=true;
            }

            if(FoundSwapchainExtension)
            {
                break;
            }
        }
        
        //find a device support  wideline feature
        bool FoundWideLineFeature=false;
        vk::PhysicalDeviceFeatures Features=PotentialPhysicalDevice.getFeatures();
        if(Features.wideLines)
        {
            FoundWideLineFeature=true;
        }


        if(FoundSwapchainExtension&&FoundWideLineFeature)
        {
            PhysicalDevice=PotentialPhysicalDevice;
        }

        AvailablePhysicalDevices.Add(PotentialPhysicalDevice);
    }
    assert(!AvailablePhysicalDevices.Empty() &&"Cant find a property Physical device");

    PhysicalDevice=AvailablePhysicalDevices[0];

    //find a DiscreteGpu gpu
    for(auto PotentialPhysicalDevice:AvailablePhysicalDevices )
    {
        if(PotentialPhysicalDevice.getProperties().deviceType ==vk::PhysicalDeviceType::eDiscreteGpu)
        {
            PhysicalDevice=PotentialPhysicalDevice;
            break;
        }
    }



    DeviceMemoryProperties=PhysicalDevice.getMemoryProperties();
}


void CVulkanContext::CreateWidgetRenderPass()
{
    //create render pass
    vk::AttachmentDescription ColorAttachmentDescription=vk::AttachmentDescription()
        .setFormat(SwapChainImageFormat)
        .setSamples(vk::SampleCountFlagBits::e1)
        .setLoadOp(vk::AttachmentLoadOp::eLoad)
        .setStoreOp(vk::AttachmentStoreOp::eStore)
        .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
        .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
        .setInitialLayout(vk::ImageLayout::eColorAttachmentOptimal)
        .setFinalLayout(vk::ImageLayout::eColorAttachmentOptimal);

    vk::AttachmentDescription DepthAttachmentDescription= vk::AttachmentDescription()
        .setFormat(WidgetDepthImageFormat)
        .setSamples(vk::SampleCountFlagBits::e1)
        .setLoadOp(vk::AttachmentLoadOp::eLoad)
        .setStoreOp(vk::AttachmentStoreOp::eStore)
        .setStencilLoadOp(vk::AttachmentLoadOp::eDontCare)
        .setStencilStoreOp(vk::AttachmentStoreOp::eDontCare)
        .setInitialLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal)
        .setFinalLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);

    vk::AttachmentReference ColorAttachmentReference=vk::AttachmentReference()
        .setAttachment(0)
        .setLayout(vk::ImageLayout::eColorAttachmentOptimal);

    vk::AttachmentReference DepthAttachmentReference=vk::AttachmentReference()
        .setAttachment(1)
        .setLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
    
    vk::SubpassDescription SubpassDescription=vk::SubpassDescription()
        .setPipelineBindPoint(vk::PipelineBindPoint::eGraphics)
        .setColorAttachmentCount(1)
        .setPColorAttachments(&ColorAttachmentReference)
        .setPDepthStencilAttachment(&DepthAttachmentReference);

    TVector<vk::SubpassDependency> SubpassDependencies = {
        vk::SubpassDependency()
        .setSrcSubpass(VK_SUBPASS_EXTERNAL)
        .setDstSubpass(0)
        .setSrcStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
        .setDstStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
        .setSrcAccessMask(vk::AccessFlagBits::eNone)
        .setDstAccessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite)
        ,

        vk::SubpassDependency()
        .setSrcSubpass(0)
        .setDstSubpass(VK_SUBPASS_EXTERNAL)
        .setSrcStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
        .setDstStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput)
        .setSrcAccessMask(vk::AccessFlagBits::eColorAttachmentRead | vk::AccessFlagBits::eColorAttachmentWrite)
        .setDstAccessMask(vk::AccessFlagBits::eNone)
    };

    TVector<vk::AttachmentDescription> AttachmentDescriptions=
    {
        ColorAttachmentDescription,
        DepthAttachmentDescription
    };

    vk::RenderPassCreateInfo RenderPassCreateInfo=vk::RenderPassCreateInfo()
        .setAttachmentCount(AttachmentDescriptions.size())
        .setPAttachments(AttachmentDescriptions.data())
        .setSubpassCount(1)
        .setPSubpasses(&SubpassDescription)
        .setDependencies(SubpassDependencies)
        ;

    WidgetRenderPass=GetDevice().createRenderPass(RenderPassCreateInfo);

}

void CVulkanContext::SelectQueue()
{
    TVector<vk::QueueFamilyProperties> QueueFamilyProperties = GetPhysicalDevice().getQueueFamilyProperties();

    for(int CurrentQueueIndex=0 ;CurrentQueueIndex<QueueFamilyProperties.size(); CurrentQueueIndex++)
    {
        // only consider situation that graphic queue is same as present queue  
        if(QueueFamilyProperties[CurrentQueueIndex].queueFlags & vk::QueueFlagBits::eGraphics 
        // &&GetPhysicalDevice().getSurfaceSupportKHR(CurrentQueueIndex,Surface)==VK_TRUE 
        )
        {
            QueueFamilyIndex=CurrentQueueIndex;
            break;
        }
    }

    assert(GetQueueFamilyIndex()!=UINT32_MAX && "can't find demand queue");
}

void CVulkanContext::CreateDevice()
{
    float const priorities[1] = {0.0};  //can't use nullptr as QueuePriorities
    vk::DeviceQueueCreateInfo queueInfo=vk::DeviceQueueCreateInfo()
                                .setQueueCount(1)
                                .setPQueuePriorities(priorities)
                                .setQueueFamilyIndex(GetQueueFamilyIndex());

    TVector<const char*> DeviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME,
#ifdef DEBUG
            //VK_KHR_SHADER_NON_SEMANTIC_INFO_EXTENSION_NAME,   //enable debug print in shader
            //VK_EXT_DEBUG_MARKER_EXTENSION_NAME, // show debug name in render doc

            VK_KHR_MAINTENANCE3_EXTENSION_NAME,
#endif
     };

    bool Support_DESCRIPTOR_INDEXING_EXTENSION=false;
    {
        auto Extensions=GetPhysicalDevice().enumerateDeviceExtensionProperties();
        
        for(auto Extension:Extensions)
        {
            if(0==strcmp(Extension.extensionName,VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME))
            {
                Support_DESCRIPTOR_INDEXING_EXTENSION=true;
                break;
            }
        }

    }
    if(Support_DESCRIPTOR_INDEXING_EXTENSION)
    {
        DeviceExtensions.Add(VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME);// for variable descriptor number in descriptor set layout
    }

    std::array<vk::DeviceQueueCreateInfo,1> QueueInfos={queueInfo};
    
    vk::PhysicalDeviceDescriptorIndexingFeaturesEXT DescriptorIndexing =vk::PhysicalDeviceDescriptorIndexingFeaturesEXT()
    .setShaderSampledImageArrayNonUniformIndexing(VK_TRUE)
    .setDescriptorBindingVariableDescriptorCount(VK_TRUE)
    .setRuntimeDescriptorArray(VK_TRUE)
    ;

    vk::PhysicalDeviceFeatures  DeviceFeatures=vk::PhysicalDeviceFeatures()
        .setWideLines(true);

    vk::DeviceCreateInfo DeviceInfo=vk::DeviceCreateInfo()
            //.setPNext(&DescriptorIndexing)
            .setEnabledExtensionCount((uint32_t)DeviceExtensions.size())
            .setPpEnabledExtensionNames(DeviceExtensions.data())
            .setQueueCreateInfos(QueueInfos)
            .setPEnabledFeatures(&DeviceFeatures)
            ;

    if(Support_DESCRIPTOR_INDEXING_EXTENSION)
    {
        DeviceInfo.setPNext(&DescriptorIndexing);
    }


    Device=GetPhysicalDevice().createDevice(DeviceInfo);

    GraphicQueue=GetDevice().getQueue(GetQueueFamilyIndex(),0);
    PresentQueue=   GraphicQueue;


}

// void CVulkanContext::InitializeDevice(vk::SurfaceKHR Surface)
// {
//     SelectQueue(Surface);
//     CreateDevice();
  
//     VkDebug::debugmarker::setup(GetDevice());
// }

uint32_t CVulkanContext::GetMemoryTypeIndex(vk::MemoryRequirements Requirment,vk::MemoryPropertyFlags RequiredFlag)
{
    auto MemoryTypeBits = Requirment.memoryTypeBits;
    for (uint32_t CurrentTypeIndex = 0; CurrentTypeIndex < GetDeviceMemoryProperties().memoryTypeCount; CurrentTypeIndex++) {
        if ((MemoryTypeBits & 1) == 1) {
            // Type is available, does it match user properties?
            if ((GetDeviceMemoryProperties().memoryTypes[CurrentTypeIndex].propertyFlags & RequiredFlag)
                == RequiredFlag) 
            {
                return CurrentTypeIndex;
            }
        }
        MemoryTypeBits >>= 1;
    }

    assert(false&&"Require Memory type index failed !");
    return 0;
}

vk::Format CVulkanContext::GetSwapChainImageFormat()
{
    return SwapChainImageFormat;
}

vk::Format CVulkanContext::GetWidgetDepthImageFormat()
{
    return WidgetDepthImageFormat;
}

vk::RenderPass CVulkanContext::GetWidgetRenderPass()
{
    return WidgetRenderPass;
}

vk::Fence CVulkanContext::GetConvertImageLayoutFence()
{
    return ConvertImageLayoutFence;
}

vk::CommandBuffer CVulkanContext::GetConvertImageLayoutCommandBuffer()
{
    return ConvertImageLayoutCommandBuffer;
}

vk::Fence CVulkanContext::GetCopyImageFence()
{
    return CopyImageFence;
}

vk::CommandBuffer CVulkanContext::GetCopyImageCommandBuffer()
{
    return CopyImageCommandBuffer;
}

SWidgetPipelines *CVulkanContext::GetWidgetPipelines()
{
    return &CanvasWidgetPipeline;
}

STextWidgetPipeline * CVulkanContext::GetTextWidgetPipeline()
{
    return &TextWidgetPipeline;
}

SForegroundMeshPipeline *CVulkanContext::GetForegroundMeshPipeline()
{
    return &ForegroundMeshPipeline;
}

SRectWidgetPipeline* CVulkanContext::GetRectWidgetPipeline()
{
    return &RectWidgetPipeline;
}

vk::Sampler CVulkanContext::GetDefaultImageSampler()
{
    return DefaultImageSampler;
}

SVulkanDescriptorLayout CVulkanContext::GetImageWidgetDescriptorSetLayout()
{
    return ImageWidgetDescriptorSetLayout;
}

vk::PipelineLayout CVulkanContext::GetImageWidgetPipelineLayout()
{
    return ImageWidgetPipelineLayout;
}

vk::Pipeline CVulkanContext::GetImageWidgetPipeline()
{
    return ImageWidgetPipeline;
}

// SVulkanDescriptorLayout CVulkanContext::GetTextWidgetDescriptorSetLayout()
// {
//     return TextWidgetDescriptorSetLayout;
// }

// vk::PipelineLayout CVulkanContext::GetTextWidgetPipelineLayout()
// {
//     return TextWidgetPipelineLayout;
// }

// vk::Pipeline CVulkanContext::GetTextWidgetPipeline()
// {
//     return TextWidgetPipeline;
// }

// vk::Sampler CVulkanContext::GetTextImageSampler()
// {
//     return TextImageSampler;
// }

void CVulkanContext::CreateConvertImageLayoutFence()
{
    vk::FenceCreateInfo FenceCreateInfo=vk::FenceCreateInfo();
    ConvertImageLayoutFence=GetDevice().createFence(FenceCreateInfo);
}

void CVulkanContext::CreateConvertImageLayoutCommandBuffer()
{
    vk::CommandBufferAllocateInfo CommandBufferAllocateInfo=vk::CommandBufferAllocateInfo()
    .setCommandPool(GetRenderThreadCommandPool())
    .setLevel(vk::CommandBufferLevel::ePrimary)
    .setCommandBufferCount(1);

    ConvertImageLayoutCommandBuffer=GetDevice().allocateCommandBuffers(CommandBufferAllocateInfo)[0];
}

void CVulkanContext::CreateCopyImageFence()
{
    vk::FenceCreateInfo FenceCreateInfo=vk::FenceCreateInfo();
    CopyImageFence=GetDevice().createFence(FenceCreateInfo);
}

void CVulkanContext::CreateCopyImageCommandBuffer()
{
    vk::CommandBufferAllocateInfo CommandBufferAllocateInfo=vk::CommandBufferAllocateInfo()
    .setCommandPool(GetRenderThreadCommandPool())
    .setLevel(vk::CommandBufferLevel::ePrimary)
    .setCommandBufferCount(1);

    CopyImageCommandBuffer=GetDevice().allocateCommandBuffers(CommandBufferAllocateInfo)[0];
}

void CVulkanContext::CreateImageWidgetThings()
{
    //have a push constant for vertex shader, do not need vertex buffer
    //have a descriptor set for fragment shader, which contains a texture2D

    TVector<vk::DescriptorSetLayoutBinding> DescriptorSetLayoutBindings;
    DescriptorSetLayoutBindings.Add(vk::DescriptorSetLayoutBinding()
        .setBinding(0)
        .setDescriptorType(vk::DescriptorType::eCombinedImageSampler)
        .setDescriptorCount(1)
        .setStageFlags(vk::ShaderStageFlagBits::eFragment)
    );

    vk::DescriptorSetLayoutCreateInfo DescriptorSetLayoutCreateInfo = vk::DescriptorSetLayoutCreateInfo()
        .setBindings(DescriptorSetLayoutBindings);


    ImageWidgetDescriptorSetLayout.Layout =GetDevice().createDescriptorSetLayout(DescriptorSetLayoutCreateInfo);
    ImageWidgetDescriptorSetLayout.DescriptorNums.CombinedImageSamplerDescriptorNum=1;

    //create pipeline layout
    TVector<vk::PushConstantRange> PushConstantRanges=
    {
        vk::PushConstantRange()
        .setStageFlags(vk::ShaderStageFlagBits::eVertex)
        .setOffset(0)
        .setSize(sizeof(SImageWidgetVertexPushConstant))
    };

    vk::PipelineLayoutCreateInfo PipelineLayoutCreateInfo = vk::PipelineLayoutCreateInfo()
        .setSetLayouts(ImageWidgetDescriptorSetLayout.Layout)
        .setPushConstantRanges(PushConstantRanges);

    ImageWidgetPipelineLayout =GetDevice().createPipelineLayout(PipelineLayoutCreateInfo);

    //create pipeline
    auto VertexShader=GetShaderManager()->GetVulkanOnlyShader(U"ImageWidgetVertex");
    auto FragmentShader=GetShaderManager()->GetVulkanOnlyShader(U"ImageWidgetFragment");
    
    //dynamic state
    vk::DynamicState DynamicState[2]={vk::DynamicState::eViewport,vk::DynamicState::eScissor};

    vk::PipelineDynamicStateCreateInfo PipelineDynamicStateCreateInfo=vk::PipelineDynamicStateCreateInfo()
        .setDynamicStateCount(2)
        .setPDynamicStates(DynamicState);

    vk::PipelineShaderStageCreateInfo PipelineShaderStageCreateInfo[2];
    PipelineShaderStageCreateInfo[0]=vk::PipelineShaderStageCreateInfo()
        .setStage(vk::ShaderStageFlagBits::eVertex)
        .setModule(VertexShader->Module)
        .setPName("main");

    PipelineShaderStageCreateInfo[1]=vk::PipelineShaderStageCreateInfo()
        .setStage(vk::ShaderStageFlagBits::eFragment)
        .setModule(FragmentShader->Module)
        .setPName("main");

    vk::PipelineVertexInputStateCreateInfo PipelineVertexInputStateCreateInfo=vk::PipelineVertexInputStateCreateInfo()
        .setVertexBindingDescriptionCount(0)
        .setVertexAttributeDescriptionCount(0);

    vk::PipelineInputAssemblyStateCreateInfo PipelineInputAssemblyStateCreateInfo=vk::PipelineInputAssemblyStateCreateInfo()
        .setTopology(vk::PrimitiveTopology::eTriangleStrip);
    
    vk::PipelineViewportStateCreateInfo PipelineViewportStateCreateInfo=vk::PipelineViewportStateCreateInfo()
        .setViewportCount(1)
        .setScissorCount(1);

    vk::PipelineRasterizationStateCreateInfo PipelineRasterizationStateCreateInfo=vk::PipelineRasterizationStateCreateInfo()
        .setPolygonMode(vk::PolygonMode::eFill)
        .setCullMode(vk::CullModeFlagBits::eNone)
        .setFrontFace(vk::FrontFace::eClockwise)
        .setLineWidth(1.0f);

    vk::PipelineMultisampleStateCreateInfo PipelineMultisampleStateCreateInfo=vk::PipelineMultisampleStateCreateInfo()
        .setRasterizationSamples(vk::SampleCountFlagBits::e1);

    vk::PipelineDepthStencilStateCreateInfo PipelineDepthStencilStateCreateInfo=vk::PipelineDepthStencilStateCreateInfo()
        .setDepthTestEnable(true)
        .setDepthWriteEnable(true)
        .setDepthCompareOp(vk::CompareOp::eLessOrEqual)
        .setDepthBoundsTestEnable(false)
        .setStencilTestEnable(false);

    vk::PipelineColorBlendAttachmentState PipelineColorBlendAttachmentState=vk::PipelineColorBlendAttachmentState()

        .setColorWriteMask(
            vk::ColorComponentFlagBits::eR
            |vk::ColorComponentFlagBits::eG
            |vk::ColorComponentFlagBits::eB
            |vk::ColorComponentFlagBits::eA
        )
        .setBlendEnable(true) //color might be transparent
        .setSrcColorBlendFactor(vk::BlendFactor::eSrcAlpha)
        .setDstColorBlendFactor(vk::BlendFactor::eOneMinusSrcAlpha)
        .setColorBlendOp(vk::BlendOp::eAdd)
        .setSrcAlphaBlendFactor(vk::BlendFactor::eOne)
        .setDstAlphaBlendFactor(vk::BlendFactor::eZero)
        .setAlphaBlendOp(vk::BlendOp::eAdd)
        ; 

    vk::PipelineColorBlendStateCreateInfo PipelineColorBlendStateCreateInfo=vk::PipelineColorBlendStateCreateInfo()
        .setAttachmentCount(1)
        .setPAttachments(&PipelineColorBlendAttachmentState);

    vk::GraphicsPipelineCreateInfo GraphicsPipelineCreateInfo=vk::GraphicsPipelineCreateInfo()
        .setPDynamicState(&PipelineDynamicStateCreateInfo)
        .setStageCount(2)
        .setPStages(PipelineShaderStageCreateInfo)
        .setPVertexInputState(&PipelineVertexInputStateCreateInfo)
        .setPInputAssemblyState(&PipelineInputAssemblyStateCreateInfo)
        .setPViewportState(&PipelineViewportStateCreateInfo)
        .setPRasterizationState(&PipelineRasterizationStateCreateInfo)
        .setPMultisampleState(&PipelineMultisampleStateCreateInfo)
        .setPDepthStencilState(&PipelineDepthStencilStateCreateInfo)
        .setPColorBlendState(&PipelineColorBlendStateCreateInfo)
        .setLayout(ImageWidgetPipelineLayout)
        .setRenderPass(GetWidgetRenderPass())
        .setSubpass(0);

    ImageWidgetPipeline=GetDevice().createGraphicsPipeline(nullptr,GraphicsPipelineCreateInfo).value;    

    //create sampler
    vk::SamplerCreateInfo SamplerCreateInfo=vk::SamplerCreateInfo()
        .setMagFilter(vk::Filter::eLinear)
        .setMinFilter(vk::Filter::eLinear)
        .setAddressModeU(vk::SamplerAddressMode::eRepeat)
        .setAddressModeV(vk::SamplerAddressMode::eRepeat)
        .setAddressModeW(vk::SamplerAddressMode::eRepeat)
        .setAnisotropyEnable(false)
        .setMaxAnisotropy(1)
        .setBorderColor(vk::BorderColor::eIntOpaqueBlack)
        .setUnnormalizedCoordinates(false)
        .setCompareEnable(false)
        .setCompareOp(vk::CompareOp::eAlways)
        .setMipmapMode(vk::SamplerMipmapMode::eLinear)
        .setMipLodBias(0.0f)
        .setMinLod(0.0f)
        .setMaxLod(0.0f);

    DefaultImageSampler=GetDevice().createSampler(SamplerCreateInfo);
}

std::shared_ptr<CVulkanTexture2D> CVulkanContext::ToVulkanTexture2D(TThreadSafeSharedPtr<CTexture2DPixels> InTexture2D)
{
    return Texture2DMangers->FindVulkanObj(InTexture2D);
}

std::shared_ptr<CVulkanTextureCube> CVulkanContext::ToVulkanTextureCube(TThreadSafeSharedPtr<CWriteInTextureCube> InTextureCube)
{
    return TextureCubeMangers->FindVulkanObj(InTextureCube);
}

std::shared_ptr<CVulkanMesh> CVulkanContext::ToVulkanMesh(TThreadSafeSharedPtr<CWriteInMesh> InMesh)
{
    return MeshMangers->FindVulkanObj(InMesh);
}

std::shared_ptr<CVulkanShader> CVulkanContext::ToVulkanShader(TThreadSafeSharedPtr<CWriteInShader> InShader)
{
    return ShadersMangers->FindVulkanObj(InShader);
}

std::shared_ptr<CVulkanMaterial> CVulkanContext::ToVulkanMaterial(std::shared_ptr<CPreRenderMaterial> InMaterial)
{
    return MaterialsMangers[CurrentBufferIndex]->FindVulkanObj(InMaterial);
}

TVector<vk::VertexInputAttributeDescription> CVulkanContext::GetMeshVertexInputAttributeDescriptions()
{
    TVector<vk::VertexInputAttributeDescription> Result=
    {
        vk::VertexInputAttributeDescription()
            .setBinding(0)
            .setLocation(0)
            .setFormat(vk::Format::eR32G32B32Sfloat)
            .setOffset(offsetof(SVertex,Position)),
        vk::VertexInputAttributeDescription()
            .setBinding(0)
            .setLocation(1)
            .setFormat(vk::Format::eR32G32Sfloat) 
            .setOffset(offsetof(SVertex,UV)),
        vk::VertexInputAttributeDescription()
            .setBinding(0)
            .setLocation(2)
            .setFormat(vk::Format::eR32G32B32Sfloat) 
            .setOffset(offsetof(SVertex,Normal))        
    };
    return Result;
}

TVector<vk::VertexInputBindingDescription> CVulkanContext::GetMeshVertexInputBindingDescriptions()
{
        TVector<vk::VertexInputBindingDescription> Ret={
            vk::VertexInputBindingDescription()
                .setBinding(0)
                .setStride(sizeof(SVertex))
        };
        return Ret;
}

void CVulkanContext::VulkanThreadRun()
{   
    MemoryPools.Init();
    
    //create command pool
    {
        vk::CommandPoolCreateInfo CommandPoolInfo=vk::CommandPoolCreateInfo()
        .setQueueFamilyIndex(GetQueueFamilyIndex())
        .setFlags(vk::CommandPoolCreateFlagBits::eResetCommandBuffer);

        RenderThreadCommandPool=GetDevice().createCommandPool(CommandPoolInfo);
    }

    SceneGlobal.Init();
    
    CreateWidgetRenderPass();

    RectWidgetPipeline.Init();

    CreateConvertImageLayoutFence();
    CreateConvertImageLayoutCommandBuffer();

    CreateCopyImageFence();
    CreateCopyImageCommandBuffer();

    CreateImageWidgetThings();
    CanvasWidgetPipeline.Init();
    TextWidgetPipeline.Init();

    ForegroundMeshPipeline.Init();

    RenderThreadInitialized=true;

    while(VulkanThreadRunning)
    {
        while(!RRenderContext::Get()->PreProcessResult.load())
        {
            std::this_thread::yield();
        }

        BEGIN_FRAME_TIME_COUNT(RenderThread);

        auto PreProcessResult=RRenderContext::Get()->PreProcessResult.load();
        RRenderContext::Get()->PreProcessResult.store(nullptr);

        //将预渲染资源转换为vulkan资源
        Texture2DMangers->UpdateTextures(PreProcessResult->Texture2Ds);
        TextureCubeMangers->UpdateTextures(PreProcessResult->TextureCubes);
        ShadersMangers->UpdateShaders(PreProcessResult->Shaders);
        MaterialsMangers[CurrentBufferIndex]->UpdateMaterials(
            PreProcessResult->Materials
            ,ShadersMangers.get()
            ,Texture2DMangers.get()
            ,TextureCubeMangers.get()
        );
        MeshMangers->UpdateMeshs(PreProcessResult->Meshes);

        //绘制
        this->DrawWidgets(PreProcessResult);

        delete PreProcessResult;

        END_FRAME_TIME_COUNT(RenderThread);

        GotoNextFrame();
    }
}
void CVulkanContext::DrawWidgets(CAllPreRenderData* InWindows)
{
    auto FormerWindows=VulkanWindowMap;
    VulkanWindowMap.Clear();
    
    if(InWindows->Windows.Empty())
    {
        //没有窗口，无需渲染
        return;
    }

    for(auto& PreprocessWindow:InWindows->Windows)
    {
        if(!FormerWindows.Contains(PreprocessWindow->SystemWindow->GetWindowID()))
        {
            VulkanWindowMap.Add(
                PreprocessWindow->SystemWindow->GetWindowID()
                ,std::make_shared<CVulkanWindow>(PreprocessWindow->SystemWindow->GetSystemWindow()->CreateVkSurfaceKHR(VkInstance)));
        }
        else
        {
            VulkanWindowMap.Add(
                PreprocessWindow->SystemWindow->GetWindowID()
                ,FormerWindows[PreprocessWindow->SystemWindow->GetWindowID()]);
        }
    }
    FormerWindows.Clear();

    auto VulkanWindows=VulkanWindowMap.Values();

    for(auto& Window: VulkanWindows)
    {
        Window->PrepareFrame();
    }

    //wait and reset render fence
    for(auto& Window: VulkanWindows)
    {   
        Window->WaitFormerFrame();
    }

    //在这个点之后，所有前一帧的资源都已经完成了
    //可以安全的清理回收资源
    RecycleObjects.Recycle(GetDevice(),RenderThreadCommandPool,GetMemoryPools());

    //destroy descriptor pool
    AutoResetDescriptorPool[CurrentBufferIndex].ClearPools();

    for(auto& PreprocessWindow:InWindows->Windows)
    {
        VulkanWindowMap[PreprocessWindow->SystemWindow->GetWindowID()]
            ->PrepareRecord(PreprocessWindow->AllVulkanWidgets);
    }

    //创建自动重置的描述符池
    AutoResetDescriptorPool[CurrentBufferIndex].CreatePools();

    for(auto& Window: VulkanWindows)
    {
        Window->CreateRecordTasks();
    }

    for(auto& Window : VulkanWindows)
    {
        Window->RecordPrimaryCommandBuffer();
    }

    //submit every surface's primary command buffer
    for(auto& Window : VulkanWindows)
    {
        Window->Submit();
    }

    for(auto& Window: VulkanWindows)
    {
        Window->PresentFrame();
    }

}

